package custom;


import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * 生成代理对象的代码
 * @author cctv
 */
public class CCTVProxy {

    private static String ln = "\r\n";

    public static Object newProxyInstance(CCTVClassLoader loader, Class<?>[] interfaces, CCTVInvocationHandler h) {

        try {

            // 1 生成源代码 (这只做演示取第一个接口)
            String proxySrc = generateSrc(interfaces[0]);

            // 2 将生成的源代码输出到磁盘，保存为.java文件 ($符合开始的名字就是代理类)
            String filePath = CCTVProxy.class.getResource("").getPath();
            File f = new File(filePath + "$Proxy0.java");
            FileWriter fw = new FileWriter(f);
            fw.write(proxySrc);
            fw.flush();
            fw.close();

            //3 编译源代码 并生成.class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = manager.getJavaFileObjects(f);
            JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null,iterable);
            task.call();
            manager.close();

            //4 将class文件中的内容 动态加载到jvm中来
            Class proxyClass = loader.findClass("$Proxy0");
            Constructor c = proxyClass.getConstructor(CCTVInvocationHandler.class);
            f.delete();

            //5 返回被代理后的代理对象
            return c.newInstance(h);

        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }

    private static String generateSrc(Class<?> interfaces) {
        StringBuffer src = new StringBuffer();
        src.append("package custom;" + ln);
        src.append("import java.lang.reflect.Method;" + ln);
        src.append("public class  $Proxy0 implements  " + interfaces.getName() + "{" + ln);

        src.append("CCTVInvocationHandler h;" + ln);

        src.append("public $Proxy0(CCTVInvocationHandler h){" + ln);
        src.append("this.h = h;" + ln);
        src.append("}" + ln);
        for (Method m : interfaces.getMethods()) {
            src.append("public " + m.getReturnType().getName() + " " + m.getName() + "(){" + ln);
            src.append("try{"+ln);
            src.append("Method m = " + interfaces.getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{});" + ln);
            src.append("this.h.invoke(this,m,null);" + ln);
            src.append("}catch(Throwable e){ e.printStackTrace();}"+ln);
//            演示简化下  不然return类型太多了 这里代码很多
            if(!m.getReturnType().getName().equals("void")){
                src.append("return null;");
            }
            src.append("}" + ln);
        }

        src.append("}");

        return src.toString();

    }
}
